<template>
	<div class="layout-pd">
		<el-card shadow="hover" header="构建交互式可视化图--gojs">
			<div id="myDiagramDiv"
				style="border: 1px solid #ccc; background-color: rgb(232, 232, 232); width: 100%; height: 700px; position: relative; -webkit-tap-highlight-color: rgba(255, 255, 255, 0);">
				<canvas tabindex="0" width="1996" height="1396"
					style="position: absolute; top: 0px; left: 0px; z-index: 2; user-select: none; touch-action: none; width: 998px; height: 698px;"></canvas>
				<div style="position: absolute; overflow: auto; width: 998px; height: 698px; z-index: 1;">
					<div style="position: absolute; width: 1px; height: 1px;"></div>
				</div>
			</div>
		</el-card>
	</div>
</template>

<script setup lang="ts" name="tools">
import { reactive, onMounted, onUnmounted, nextTick, toRefs } from 'vue';
import * as go from 'gojs';

const $ = go.GraphObject.make;


// 定义变量内容
const state = reactive({

});
let myDiagram = {};
// This sample defines several custom Shape geometries
const tank1 = 'F M 0 0 L 0 75 25 100 50 75 50 0z' // 50x100 sized-shape
const tank2 = 'F M 0 0 L 0 100 10 100 10 90 40 90 40 100 50 100 50 0z' // 50x100 sized-shape
const tank3 = 'F M 0 100 L 0 25 A 25 25 0 0 1 50 25 L 50 100 z' // 50x100 sized-shape

const labelLeft = 'F M 0 20 L 30 40 100 40 100 0 30 0 z'
const labelRight = 'F M 0 0 L 70 0 100 20 70 40 0 40 z'

const valve = 'F1 M0 0 L40 20 40 0 0 20z M20 10 L20 30 M12 30 L28 30';
const pump = 'F M 8 10 A 2 2 0 1 1 6 8 L 9 8 L 9 10 Z M 5 11 A 1 1 0 0 1 7 9';
const sensor = 'F M 0 0 L 15 15 L 15 20 L 5 20 L 5 15 L 0 15 L 0 10 L -2 10 L -2 4 L 0 4 Z';

const colors = {
	black: '#151c26',
	white: '#ffffff',
	gray: '#151c26',
	green: '#7ba961',
	blue: '#00a9b0',
	pink: '#e483a2',
	yellow: '#f9c66a',
	orange: '#e48042',
	red: '#ed2d44'
}
const initDiagram = () => {
	// const { } = toRefs(state)
	myDiagram = $(go.Diagram, "myDiagramDiv",//为DIV.HTML元素创建一个画布
		{
			'animationManager.isEnabled': false,
			'undoManager.isEnabled': true,
			"rotatingTool.snapAngleMultiple": 90,
			"rotatingTool.snapAngleEpsilon": 45
		}
	);



	const textDefaults = { font: '10px Inter, sans-serif', stroke: colors.white };

	// Tanks have a variable number of connection ports.
	// Each port must specify its location on the tank (alignment spot)
	// And potentially its fromSpot or toSpot
	const tankPort = new go.Panel()
		.bind('alignment', 'a')
		.bind('portId', 'p')
		.bind('fromSpot', 'fs')
		.bind('toSpot', 'ts')
		.add(new go.Shape("Diamond", { width: 10, height: 10, fill: colors.green }));

	// Base template is a shape with a label
	myDiagram.nodeTemplateMap.add('',
		// Outer spot panel holding inner spot panel (main element) and ports
		new go.Node('Spot', {
			itemTemplate: tankPort
		}).bind("location", "pos", go.Point.parse, go.Point.stringify)
			.bind('itemArray', 'ports')
			.add(
				// Inner spot panel holding Shape and Text label
				new go.Panel('Spot')
					.add(
						new go.Shape({
							geometryString: tank1,
							strokeWidth: 1,
							stroke: 'gray',
							width: 75, height: 140,
							fill: new go.Brush("Linear", {
								0.3: colors.gray,
								0.5: go.Brush.lightenBy(colors.gray, 0.5),
								1.0: colors.gray,
								start: go.Spot.Left, end: go.Spot.Right
							}),

						})

							.bind('width').bind('height')
							.bind('geometryString', 'tankType')
							// .bind('stroke', 'color')
							.bind('fill', 'color', (c) => new go.Brush("Linear", {
								0.0: c,
								0.5: go.Brush.lightenBy(c, 0.8),
								1.0: c,
								start: go.Spot.Left, end: go.Spot.Right
							})),
						new go.TextBlock({ font: 'bold 13px Inter, sans-serif', stroke: colors.black }).bind(
							'text',
							'key'
						)
					)));

	myDiagram.nodeTemplateMap.add('label',
		new go.Node('Auto', {}).bind("location", "pos", go.Point.parse, go.Point.stringify)
			.add(
				new go.Shape({
					portId: '',
					fromSpot: go.Spot.Right, toSpot: go.Spot.LeftRightSides,
					geometryString: labelRight,
					strokeWidth: 4,
					// width: 100, height: 40,
					fill: colors.gray
				}).bind('width').bind('height')
					.bind('geometryString', 'direction', (d) => d === 'right' ? labelRight : labelLeft)
					.bind('stroke', 'color'),
				new go.TextBlock({
					margin: new go.Margin(8, 40, 8, 8),
					textAlign: 'center',
					font: '12px sans-serif',
					stroke: colors.white,
					alignment: new go.Spot(0.1, 0.5)
				})
					.bind('margin', 'direction', (d) => d === 'right' ? new go.Margin(8, 40, 8, 8) : new go.Margin(8, 8, 8, 40))
					.bind('alignment', 'direction', (d) => d === 'right' ? new go.Spot(0.3, 0.5) : new go.Spot(0.7, 0.5))
					.bind('text')
			));

	myDiagram.nodeTemplateMap.add("valve",
		new go.Node("Vertical",
			{
				locationSpot: new go.Spot(0.5, 1, 0, -21), locationObjectName: "SHAPE",
				selectionObjectName: "SHAPE", rotatable: true
			})
			.bindTwoWay("angle")
			.bind("location", "pos", go.Point.parse, go.Point.stringify)
			.add(
				new go.TextBlock(
					{ background: colors.gray, alignment: go.Spot.Center, textAlign: "center", margin: 2, editable: true })
					.set(textDefaults)
					.bind("text", 'key')
					// keep the text upright, even when the whole node has been rotated upside down
					.bindObject("angle", "angle", a => a === 180 ? 180 : 0),
				new go.Shape(
					{
						name: "SHAPE",
						geometryString: valve,
						strokeWidth: 2,
						portId: "", fromSpot: new go.Spot(1, 0.35), toSpot: new go.Spot(0, 0.35)
					}).bind('fill', 'color').bind('stroke', 'color', (c) => go.Brush.darkenBy(c, 0.3))
			)
	);

	myDiagram.nodeTemplateMap.add("pump",
		new go.Node("Vertical",
			{
				locationSpot: new go.Spot(0.5, 1, 0, -21), locationObjectName: "SHAPE",
				selectionObjectName: "SHAPE", rotatable: true
			})
			.bindTwoWay("angle")
			.bind("location", "pos", go.Point.parse, go.Point.stringify)
			.add(
				new go.TextBlock(
					{ background: colors.gray, alignment: go.Spot.Center, textAlign: "center", margin: 2, editable: true })
					.set(textDefaults)
					.bind("text", 'key')
					// keep the text upright, even when the whole node has been rotated upside down
					.bindObject("angle", "angle", a => a === 180 ? 180 : 0),
				new go.Shape(
					{
						name: "SHAPE",
						geometryString: pump,
						width: 45, height: 40,
						strokeWidth: 2,
						portId: "", fromSpot: new go.Spot(1, 0.25), toSpot: new go.Spot(0, 0.5)
					}).bind('fill', 'color').bind('stroke', 'color', (c) => Brush.darkenBy(c, 0.3))
			)
	);

	// This is a component of the "monitor" node template
	const valuesTableItem = new go.Panel('TableRow')
		.add(
			new go.TextBlock("").set(textDefaults).bind('text', 'label'),
			new go.Panel("Spot", { column: 1 })
				.add(
					new go.Shape({ stroke: colors.orange, fill: colors.gray, margin: 2, width: 40, height: 15 }),
					new go.TextBlock("", {}).set(textDefaults).bind('text', 'value')
				),
			new go.TextBlock("", { column: 2, alignment: go.Spot.Left }).set(textDefaults).bind('text', 'unit'),
		)
	const valuesTable = new go.Panel("Table",
		{ strech: go.Stretch.Horizontal, itemTemplate: valuesTableItem })
		.bind('itemArray', 'values');

	// This is a component of the "monitor" node template, showing a dynamic number of status blocks
	const statusPanelTemplate = new go.Panel('Spot')
		.add(
			new go.Shape({ width: 18, height: 18, fill: colors.white }).bind('fill'),
			new go.TextBlock().set(textDefaults).bind('text')
		)
	const statusPanel = new go.Panel("Horizontal", {
		width: 90, height: 20,
		itemTemplate: statusPanelTemplate
	}).bind('itemArray', 'statuses')


	// Monitor node for monitoring values, linked to a pump or valve
	myDiagram.nodeTemplateMap.add("monitor",
		new go.Node("Auto")
			.bind("location", "pos", go.Point.parse, go.Point.stringify)
			.add(
				new go.Shape({ fill: colors.gray, stroke: colors.white, strokeWidth: 2 }),
				new go.Panel("Vertical", { margin: 4 })
					// Title
					.add(new go.TextBlock("Title", { strech: go.Stretch.Horizontal }).set(textDefaults).bind('text', 'title'))
					// Notifications
					.add(statusPanel)
					// Values
					.add(valuesTable)
			)
	);

	// Sensor node, linked to a tank
	myDiagram.nodeTemplateMap.add("sensor",
		new go.Node("Vertical")
			.bind("location", "pos", go.Point.parse, go.Point.stringify)
			.add(
				new go.Panel("Horizontal", { margin: 4 })
					.add(
						new go.Shape({ fill: colors.gray, stroke: colors.white, strokeWidth: 2, geometryString: sensor, portId: '', fromSpot: new go.Spot(0, 0.4, 0, 0), }),
						new go.TextBlock({ margin: 2 }).set(textDefaults).bind('text', 'key')
					),
				new go.Panel("Horizontal")
					.add(
						new go.Panel("Spot", { column: 1 })
							.add(
								new go.Shape({ stroke: colors.orange, fill: colors.gray, margin: 2, width: 40, height: 15 }),
								new go.TextBlock("", {}).set(textDefaults).bind('text', 'value')
							),
						new go.TextBlock("", { column: 2, alignment: go.Spot.Left }).set(textDefaults).bind('text', 'unit'),
					)
			)
	);


	myDiagram.linkTemplateMap.add('',
		new go.Link({
			routing: go.Routing.AvoidsNodes, corner: 12, layerName: 'Background',
			toShortLength: 3,
		})
			.bind('fromEndSegmentLength', 'fromEndSeg')
			.bind('toEndSegmentLength', 'toEndSeg')
			.add(new go.Shape({ strokeWidth: 7, stroke: colors.gray, isPanelMain: true }))
			.add(
				new go.Shape({ strokeWidth: 3, stroke: colors.green, isPanelMain: true })
					.bind('stroke', 'color')
			)
			.add(new go.Shape({ stroke: colors.green, fill: colors.green, toArrow: 'Triangle' }).bind('stroke', 'color').bind('fill', 'color'))
			.add(new go.TextBlock({ segmentOffset: new go.Point(0, -10), background: colors.gray }).set(textDefaults).bind('text'))
	)

	myDiagram.linkTemplateMap.add('monitor',
		new go.Link({
			curve: go.Curve.Bezier, layerName: 'Background',
			fromSpot: go.Spot.Top, fromEndSegmentLength: 30
		})
			.bind('fromSpot', 'fs')
			.bind('toSpot', 'ts')
			.add(
				new go.Shape({ strokeWidth: 3, stroke: colors.white, strokeDashArray: [3, 4], isPanelMain: true })
					.bind('stroke', 'color')
			)
	)

	myDiagram.linkTemplateMap.add('sensor',
		new go.Link({
			layerName: 'Background',
		})
			.add(
				new go.Shape({ strokeWidth: 1.5, stroke: colors.red, strokeDashArray: [2, 2] })
			)
	)
	
	// myDiagram.model = new go.GraphLinksModel(
	// ); // end model assignment

	// Simulate data coming in to the monitor
	// This randomly assigns new data to the itemArrays in the monitor nodes
	// and the data in the sensor nodes
	setInterval(() => {
		myDiagram.commit(() => {
			const sensorKeys = ['S1', 'S2'].map(k => myDiagram.findNodeForKey(k))
			for (const n of sensorKeys) {
				const d = n.data;
				myDiagram.model.set(d, 'value', roundAndFloor(parseFloat(d.value) + random(-0.5, 0.55), 1));
			}
		}, null); // null tells the Diagram to skip the undo manager

		if (+new Date % 2 === 0) return; // do the updates below half as often
		myDiagram.commit(() => {
			const controlNodes = ['cTCV102', 'cFCV101', 'cFM102', 'cFM103'].map(k => myDiagram.findNodeForKey(k))
			for (const n of controlNodes) {
				const vals = n.data.values;
				myDiagram.model.set(vals[0], 'value', roundAndFloor(parseFloat(vals[0].value) + random(-0.5, 0.55), 1));
				myDiagram.model.set(vals[1], 'value', roundAndFloor(parseFloat(vals[1].value) + random(-0.3, 0.35), 1));
				myDiagram.model.set(vals[2], 'value', roundAndFloor(parseFloat(vals[2].value) + random(-0.2, 0.2), 1));
			}
		}, null); // null tells the Diagram to skip the undo manager

		// rarely, randomly change a monitor color block
		if (+new Date % 15 === 0) return;
		myDiagram.commit(() => {
			const controlNodes = ['cTCV102', 'cFCV101', 'cFM102', 'cFM103'].map(k => myDiagram.findNodeForKey(k))
			for (const n of controlNodes) {
				const vals = n.data.statuses;
				myDiagram.model.set(vals[0], 'fill', Math.random() > 0.5 ? colors.green : colors.white)
				myDiagram.model.set(vals[1], 'fill', Math.random() > 0.5 ? colors.yellow : colors.white);
			}
		}, null); // null tells the Diagram to skip the undo manager
	}, 550);



	load(); // load an initial diagram from some JSON text


} // end initDiagram


function roundAndFloor(num, decimalPlaces = 0) {
	num = Math.round(num + "e" + decimalPlaces);
	return Math.max(Number(num + "e" + -decimalPlaces), 0);
}
function random(min, max) {
	return Math.random() * (max - min) + min;
}

//   // Show the diagram's model in JSON format that the user may edit
//   function save() {
//     document.getElementById('mySavedModel').value = myDiagram.model.toJson();
//     myDiagram.isModified = false;
//   }
let dataJson = {

	copiesArrays: true,
	copiesArrayObjects: true,
	linkFromPortIdProperty: 'fromPort',
	linkToPortIdProperty: 'toPort',
	nodeDataArray: [
		// LABELS
		{ key: '1', category: 'label', text: 'Steam Condensate\nHeader', color: colors.red, direction: 'left', pos: "0 -20" },
		{ key: '2', category: 'label', text: 'From LP Steam\nHeader', color: colors.red, pos: "0 160" },
		{ key: '3', category: 'label', text: 'Soft Water', color: colors.green, pos: "80 240" },
		{ key: '4', category: 'label', text: 'From ME-01A', color: colors.yellow, pos: "0 299.5" },
		{ key: '5', category: 'label', text: 'To MRF-02', color: colors.yellow, direction: 'left', pos: "0 360.5" },
		{ key: '6', category: 'label', text: 'CPO+PFAO\nFrom Storage Tank', color: colors.yellow, pos: "0 423" },
		{ key: '7', category: 'label', text: 'To MCOT', color: colors.yellow, direction: 'left', pos: "0 541" },
		{ key: '8', category: 'label', text: 'To MPHE-02', color: colors.yellow, direction: 'left', pos: "0 615" },
		// TANKS
		{
			key: 'MHWT', tankType: tank3, color: colors.gray, pos: "287 19", ports: [
				{ p: 'BL1', a: new go.Spot(0, 1, 0, -50) },
				{ p: 'BL2', a: new go.Spot(0, 1, 0, -30) },
				{ p: 'BL3', a: new go.Spot(0, 1, 0, -10) },
				{ p: 'BR', fs: go.Spot.RightSide, a: new go.Spot(1, 1, 0, -30) },
				{ p: 'SensorR', type: 'sensor', ts: go.Spot.RightSide, a: new go.Spot(1, 0.5, 0, 0) }
			]
		},
		{
			key: 'MSF', color: colors.gray, pos: "244 418", ports: [
				{ p: 'TL', a: new go.Spot(0, 0, 0, 30) },
				{ p: 'BR', a: new go.Spot(1, 1, 0, -50), fs: go.Spot.Right },
				{ p: 'B', a: new go.Spot(0.5, 1, 0, 0) }
			]
		},
		{
			key: 'ME-01', color: colors.gray, tankType: tank2, pos: "297 261", width: 70, height: 120, ports: [
				{ p: 'TL', a: new go.Spot(0, 0, 0, 30) },
				{ p: 'BL', a: new go.Spot(0, 1, 0, -30) },
				{ p: 'TR', fs: go.Spot.RightSide, a: new go.Spot(1, 0, 0, 30) },
				{ p: 'BR', ts: go.Spot.RightSide, a: new go.Spot(1, 1, 0, -30) },
			]
		},
		{
			key: 'MRM', color: colors.gray, pos: "529 370", width: 60, height: 80, ports: [
				{ p: 'T1', a: new go.Spot(0, 0, 10, 0), ts: go.Spot.Top },
				{ p: 'T2', a: new go.Spot(0, 0, 30, 0), ts: go.Spot.Top },
				{ p: 'T3', a: new go.Spot(0, 0, 50, 0), ts: go.Spot.Top },
				{ p: 'B', a: new go.Spot(0.5, 1, 0, 0), fs: go.Spot.Bottom },
			]
		},
		{
			key: 'MZM', color: colors.gray, pos: "680 440", width: 50, height: 80, ports: [
				{ p: 'T', a: new go.Spot(0.5, 0, 0, 0), fs: go.Spot.Top },
				{ p: 'B', a: new go.Spot(0.5, 1, 0, 0), ts: go.Spot.Bottom },
			]
		},
		{
			key: 'MPAT', color: colors.gray, pos: "865 30", ports: [
				{ p: 'L', a: new go.Spot(0, 0.5, 0, 0), fs: go.Spot.Left },
			]
		},
		{
			key: 'MPHE-01', color: colors.gray, tankType: tank2, pos: "860 282", width: 70, height: 120, ports: [
				{ p: 'TL', a: new go.Spot(0, 0, 0, 30), fs: go.Spot.LeftSide },
				{ p: 'BL', a: new go.Spot(0, 1, 0, -30) },
				{ p: 'TR', fs: go.Spot.RightSide, a: new go.Spot(1, 0, 0, 30), ts: go.Spot.RightSide },
				{ p: 'BR', fs: go.Spot.RightSide, a: new go.Spot(1, 1, 0, -30) },
			]
		},
		{
			key: 'MHT', color: colors.gray, pos: "769 440", ports: [
				{ p: 'T', a: new go.Spot(0.5, 0, 0, 0), fs: go.Spot.Top },
				{ p: 'B', a: new go.Spot(0.5, 1, 0, 0), fs: go.Spot.Bottom },
				{ p: 'SensorB', a: new go.Spot(1, 0.7, 0, 0), type: 'sensor', ts: go.Spot.RightSide, },
			]
		},
		// VALVES
		{ key: 'TCV102', category: 'valve', color: colors.red, pos: "197 130" },
		{ key: 'FCV101', category: 'valve', color: colors.red, pos: "477 585" },
		{ key: 'LCV101', category: 'valve', color: colors.red, pos: "620 615.88", angle: 180 },
		{ key: 'FM102', category: 'valve', color: colors.white, pos: "508 167" },
		{ key: 'FM103', category: 'valve', color: colors.white, pos: "706 184", angle: 180 },
		{ key: 'FIC101', category: 'valve', color: colors.white, pos: "396 585" },
		{ key: 'P03', category: 'pump', color: colors.pink, pos: "429 178" },
		{ key: 'P04', category: 'pump', color: colors.pink, pos: "800 173.5", angle: 180 },
		{ key: 'P102', category: 'pump', color: colors.pink, pos: "720 605.3", angle: 180 },
		// MONITOR PANELS
		{
			key: 'cTCV102', title: 'Monitor TCV102', category: 'monitor', pos: "32 35",
			values: [
				{ label: 'SV', unit: '°C', value: '12.0' },
				{ label: 'PV', unit: '°C', value: '12.0' },
				{ label: 'OP', unit: '%', value: '25.0' }
			],
			statuses: [
				{ fill: colors.green },
				{ fill: colors.green },
				{ fill: colors.green }
			]
		},
		{
			key: 'cFCV101', title: 'Monitor FCV101', category: 'monitor', pos: "360 413", values: [
				{ label: 'SV', unit: 'KG/hr', value: '0.0' },
				{ label: 'PV', unit: 'KG/hr', value: '0.0' },
				{ label: 'OP', unit: '%', value: '25.0' }
			],
			statuses: [
				{ fill: colors.green },
				{ fill: colors.white },
				{ fill: colors.white }
			]
		},
		{
			key: 'cFM102', title: 'Monitor FM102', category: 'monitor', pos: "465 18", values: [
				{ label: 'SV', unit: 'KG/hr', value: '0.0' },
				{ label: 'PV', unit: 'KG/hr', value: '0.0' },
				{ label: 'OP', unit: '%', value: '25.0' }
			],
			statuses: [
				{ fill: colors.white },
				{ fill: colors.white },
			]
		},
		{
			key: 'cFM103', title: 'Monitor FM103', category: 'monitor', pos: "594 28", values: [
				{ label: 'SV', unit: 'KG/hr', value: '0.0' },
				{ label: 'PV', unit: 'KG/hr', value: '0.0' },
				{ label: 'OP', unit: '%', value: '25.0' }
			],
			statuses: [
				{ fill: colors.green },
				{ fill: colors.white },
				{ fill: colors.white }
			]
		},
		// SENSORS:
		{ key: 'S1', category: 'sensor', value: '12.0', pos: "385 68", unit: '°C' },
		{ key: 'S2', category: 'sensor', value: '12.0', pos: "870 515", unit: '°C' },
	],
	linkDataArray: [
		{ from: 'MHWT', to: '1', text: 'LPS', color: colors.red, fromPort: 'BL1' },
		{ from: 'MPHE-01', to: '1', text: 'SCH', color: colors.red, fromPort: 'BR', fromEndSeg: 25 },
		{ from: '2', to: 'TCV102', text: 'SC', color: colors.red },
		{ from: 'TCV102', to: 'MHWT', color: colors.red, toPort: 'BL2' },
		{ from: '2', to: 'MPHE-01', color: colors.red, toPort: 'TR' },
		{ from: '3', to: 'MHWT', toPort: 'BL3' },

		{ from: '4', to: 'ME-01', text: 'DO', toPort: 'TL', color: colors.yellow },
		{ from: '5', to: 'ME-01', text: 'DO', toPort: 'BL', color: colors.yellow },
		{ from: '6', to: 'MSF', text: 'CPO', color: colors.yellow, toPort: 'TL' },
		{ from: 'MSF', to: '7', text: 'CPO', color: colors.yellow, fromPort: 'B' },
		{ from: 'LCV101', to: '8', text: 'CPO', color: colors.yellow },

		{ from: 'MSF', to: 'FIC101', fromPort: 'BR' },
		{ from: 'FIC101', to: 'FCV101' },
		{ from: 'FCV101', to: 'ME-01', toPort: 'BR' },
		{ from: 'ME-01', to: 'MRM', color: colors.green, fromPort: 'TR', toPort: 'T2' },

		{ from: 'MHWT', to: 'P03', color: colors.green, fromPort: 'BR' },
		{ from: 'P03', to: 'FM102', color: colors.green },
		{ from: 'FM102', to: 'MRM', color: colors.green, toPort: 'T1' },
		{ from: 'MPAT', to: 'P04', color: colors.yellow, fromPort: 'L' },
		{ from: 'P04', to: 'FM103', color: colors.yellow },
		{ from: 'FM103', to: 'MRM', color: colors.yellow, toPort: 'T3' },
		{ from: 'MRM', to: 'MZM', fromPort: 'B', toPort: 'B', toEndSeg: 15 },
		{ from: 'MZM', to: 'MPHE-01', fromPort: 'T', toPort: 'BL' },
		{ from: 'MPHE-01', to: 'MHT', fromPort: 'TL', toPort: 'T' },
		{ from: 'P102', to: 'LCV101' },
		{ from: 'MHT', to: 'P102', fromPort: 'B' },

		{ category: 'monitor', from: 'TCV102', to: 'cTCV102', ts: go.Spot.Right },
		{ category: 'monitor', from: 'FCV101', to: 'cFCV101', ts: go.Spot.Right },
		{ category: 'monitor', from: 'FCV101', to: 'FIC101', ts: go.Spot.Top },
		{ category: 'monitor', from: 'FM102', to: 'cFM102', ts: go.Spot.Bottom },
		{ category: 'monitor', from: 'FM103', to: 'cFM103', fs: go.Spot.Bottom, ts: go.Spot.Bottom },
		// sensor links (same category)
		{ category: 'sensor', from: 'S1', to: 'MHWT', toPort: 'SensorR' },
		{ category: 'sensor', from: 'S2', to: 'MHT', toPort: 'SensorB' },
	]

}

function load() {
	myDiagram.model = new go.GraphLinksModel(dataJson)
}





onMounted(() => {
	nextTick(() => {
		initDiagram()
	})
});




</script>

<style scoped lang="scss"></style>
